package com.yfqy.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.yfqy.admin.conf.Idgenerator.SnowflakeIdGenerator;
import com.yfqy.admin.constant.MyConstants;
import com.yfqy.admin.domain.dto.attribute.AttributeDTO;
import com.yfqy.admin.domain.dto.category.AddCategory;
import com.yfqy.admin.domain.dto.category.CategoryDTO;
import com.yfqy.admin.domain.dto.category.CategoryQuery;
import com.yfqy.admin.domain.dto.category.ModifyCategory;
import com.yfqy.admin.domain.entity.Attribute;
import com.yfqy.admin.domain.entity.Category;
import com.yfqy.admin.domain.entity.CategoryAttribute;
import com.yfqy.admin.domain.entity.SysUser;
import com.yfqy.admin.enums.CategoryLevel;
import com.yfqy.admin.enums.ResponseEnum;
import com.yfqy.admin.domain.mapper.AttributeMapper;
import com.yfqy.admin.domain.mapper.CategoryAttributeMapper;
import com.yfqy.admin.domain.mapper.CategoryMapper;
import com.yfqy.admin.domain.mapper.SysUserMapper;
import com.yfqy.admin.transform.UserNameTranslator;
import com.yfqy.admin.security.login.LoginUserInfo;
import com.yfqy.admin.service.CategoryService;
import com.yfqy.admin.util.AuthUserContext;
import com.yfqy.admin.util.ExceptionTool;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService {

    private static final Logger logger = LoggerFactory.getLogger(CategoryServiceImpl.class);

    private final CategoryMapper categoryMapper;
    private final CategoryAttributeMapper categoryAttributeMapper;
    private final SnowflakeIdGenerator idGenerator;
    private final AttributeMapper attributeMapper;
    private final SysUserMapper sysUserMapper;
    private final UserNameTranslator userNameTranslator;


    @Override
    public int deleteByPrimaryKey(Long id) {
        return categoryMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(Category record) {
        return categoryMapper.insert(record);
    }

    @Override
    public int insertSelective(Category record) {
        return categoryMapper.insertSelective(record);
    }

    @Override
    public CategoryDTO selectByPrimaryKey(Long id) {
        Category category = categoryMapper.selectByPrimaryKey(id);
        if (Objects.isNull(category)) {
            ExceptionTool.throwException(ResponseEnum.CATEGORY_IS_INVALID);
        }
        Set<Long> sysUserIds = new HashSet<>();
        CategoryDTO categoryDTO = BeanUtil.toBean(category, CategoryDTO.class);
        sysUserIds.add(categoryDTO.getCreatedBy());
        sysUserIds.add(categoryDTO.getModifiedBy());
        List<AttributeDTO> attributeDTOS = Lists.newArrayList();
        // 二级分类才需要关联商品分类属性
        if (categoryDTO.getLevel() == MyConstants.BT2) {
            attributeDTOS = attributeMapper.selectByCategoryId(id);
        }
        // 所有记录中的后台管理员id
        Map<Long, SysUser> sysUserMap = Optional.ofNullable(sysUserMapper.selectByIds(new ArrayList<>(sysUserIds))).orElse(new ArrayList<>())
                .stream().collect(Collectors.toMap(SysUser::getId, Function.identity()));
        categoryDTO.setAttributeDTOS(attributeDTOS);
        /*String createdByName = Optional.ofNullable(sysUserMap.get(categoryDTO.getCreatedBy()))
                .map(user -> String.format("%s(%s)", user.getNickname(), user.getUsername())).orElse("-");
        String modifiedByName = Optional.ofNullable(sysUserMap.get(categoryDTO.getModifiedBy()))
                .map(user -> String.format("%s(%s)", user.getNickname(), user.getUsername())).orElse("-");
        categoryDTO.setCreatedByName(createdByName);
        categoryDTO.setModifiedByName(modifiedByName);*/
        userNameTranslator.translationUser(categoryDTO);
        return categoryDTO;
    }

    @Override
    public int updateByPrimaryKeySelective(Category record) {
        return categoryMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(Category record) {
        return categoryMapper.updateByPrimaryKey(record);
    }

    @Override
    public PageInfo<CategoryDTO> pageListByName(CategoryQuery categoryQuery) {
        PageHelper.startPage(categoryQuery.getPageIndex(), categoryQuery.getPageSize());
        List<CategoryDTO> categories = categoryMapper.selectListByName(categoryQuery.getName());
        if (CollUtil.isNotEmpty(categories)) {
            List<Long> ids = categories.stream().map(CategoryDTO::getId).toList();
            List<CategoryDTO> children = categoryMapper.selectByParentIds(ids);
            if (CollUtil.isNotEmpty(children)) {
                Map<Long, List<CategoryDTO>> groupByParentId = children.stream().collect(Collectors.groupingBy(CategoryDTO::getParentId));
                categories.forEach(dto -> dto.setChildren(groupByParentId.get(dto.getId())));
            }
        }
        PageInfo<CategoryDTO> pageInfo = new PageInfo<>(categories);
        PageHelper.clearPage();
        return pageInfo;
    }

    @Override
    @Transactional
    public int addCategory(AddCategory addCategory) {
        if (CategoryLevel.getLevel(addCategory.getLevel()) == null) {
            ExceptionTool.throwException(ResponseEnum.CATEGORY_LEVEL_NOT_EXIST);
        }
        // 添加二级分类需要校验一级分类
        if (addCategory.getLevel() == MyConstants.BT2) {
            if (StringUtils.isBlank(addCategory.getIcon())) {
                ExceptionTool.throwException(ResponseEnum.CATEGORY_LEVEL2_ICON_NOT_NULL);
            }
            if (MyConstants.L0.equals(addCategory.getParentId())) {
                ExceptionTool.throwException(ResponseEnum.CATEGORY_LEVEL2_NEED_LEVEL1);
            } else {
                Category parentCategory = categoryMapper.selectByPrimaryKey(addCategory.getParentId());
                if (Objects.isNull(parentCategory)) {
                    ExceptionTool.throwException(ResponseEnum.CATEGORY_PARENT_NOT_EXIT);
                }
            }
        }
        // 分类名字唯一
        Category category = categoryMapper.selectOneByName(addCategory.getName());
        if (Objects.nonNull(category)) {
            ExceptionTool.throwException(ResponseEnum.CATEGORY_IS_EXIST);
        }
        Category bean = BeanUtil.toBean(addCategory, Category.class);
        if (Objects.isNull(addCategory.getParentId())) {
            bean.setParentId(MyConstants.L0);
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long createdBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        bean.setId(idGenerator.nextId());
        bean.setCreatedBy(createdBy);
        bean.setModifiedBy(createdBy);
        int addCategoryResult = categoryMapper.insertSelective(bean);

        // 商品分类添加成功后，如果同时选择了分类对应的属性，那么一并添加
        if (addCategoryResult > MyConstants.IT0 && CollUtil.isNotEmpty(addCategory.getAttributeIds())) {
            List<Attribute> attributes = attributeMapper.selectByIds(addCategory.getAttributeIds());
            if (CollUtil.isEmpty(attributes) || attributes.size() != addCategory.getAttributeIds().size()) {
                ExceptionTool.throwException(ResponseEnum.ATTRIBUTE_NOT_EXIT);
            }
            Map<Long, Byte> attributeMap = attributes.stream().collect(Collectors.toMap(Attribute::getId, Attribute::getIsRequired));
            List<CategoryAttribute> categoryAttributes = new ArrayList<>();
            AtomicInteger sort = new AtomicInteger(1);
            addCategory.getAttributeIds().forEach(attributeId -> {
                CategoryAttribute categoryAttribute = new CategoryAttribute();
                categoryAttribute.setId(idGenerator.nextId());
                categoryAttribute.setCategoryId(bean.getId());
                categoryAttribute.setAttributeId(attributeId);
                categoryAttribute.setIsRequired(attributeMap.get(attributeId));
                categoryAttribute.setSort(sort.getAndIncrement());
                categoryAttribute.setCreatedBy(createdBy);
                categoryAttribute.setModifiedBy(createdBy);
                categoryAttributes.add(categoryAttribute);
            });
            int insertBatch = categoryAttributeMapper.insertBatch(categoryAttributes);
            logger.info("新增商品分类-添加商品关联属性-insertBatch={}", insertBatch);
        }
        return addCategoryResult;
    }

    @Override
    @Transactional
    public int modifyCategory(ModifyCategory modifyCategory) {
        Category categoryById = categoryMapper.selectByPrimaryKey(modifyCategory.getId());
        if (Objects.isNull(categoryById)) {
            ExceptionTool.throwException(ResponseEnum.CATEGORY_IS_INVALID);
        }
        Category categoryByName = categoryMapper.selectOneByName(modifyCategory.getName());
        if (Objects.nonNull(categoryByName) && !categoryByName.getId().equals(categoryById.getId())) {
            ExceptionTool.throwException(ResponseEnum.CATEGORY_IS_EXIST);
        }
        BeanUtil.copyProperties(modifyCategory, categoryById, CopyOptions.create().setIgnoreNullValue(true));
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        categoryById.setModifiedBy(modifiedBy);
        int updated = categoryMapper.updateByPrimaryKeySelective(categoryById);
        if (updated > MyConstants.IT0) {
            // 如果商品分类修改成功后 && 上传了商品分类的关联属性
            if (CollUtil.isNotEmpty(modifyCategory.getAttributeIds())) {
                // 商品分类已经绑定的属性
                Set<Long> attributeIds = categoryAttributeMapper.selectAttributeIdsByCategoryId(modifyCategory.getId());
                // 两个 set 集合不相等：商品分类当前已有的关联属性和本次编辑选择的不一致，需要删除本次没有选择的，添加本次额外选择的
                if (!attributeIds.equals(modifyCategory.getAttributeIds())) {
                    // 校验本次参数中的商品分类属性
                    List<Attribute> attributes = attributeMapper.selectByIds(modifyCategory.getAttributeIds());
                    if (CollUtil.isEmpty(attributes) || attributes.size() != modifyCategory.getAttributeIds().size()) {
                        ExceptionTool.throwException(ResponseEnum.ATTRIBUTE_NOT_EXIT);
                    }
                    // 属性id <=> 是否必填
                    Map<Long, Byte> attributeMap = attributes.stream().collect(Collectors.toMap(Attribute::getId, Attribute::getIsRequired));
                    // 取两个set的交集
                    Collection<Long> intersection = CollUtil.intersection(attributeIds, modifyCategory.getAttributeIds());
                    attributeIds.removeAll(intersection);
                    modifyCategory.getAttributeIds().removeAll(intersection);
                    // 删除本次没有选择的
                    if (CollUtil.isNotEmpty(attributeIds)) {
                        int deleteNum = categoryAttributeMapper.updateStatusByCategoryByIdAndAttributeIds(modifyCategory.getId(), attributeIds, modifiedBy);
                        logger.info("编辑商品分类-删除本次没有选择的商品关联属性-deleteNum={}", deleteNum);
                    }
                    // 添加本次额外选择的
                    if (CollUtil.isNotEmpty(modifyCategory.getAttributeIds())) {
                        AtomicInteger sort = new AtomicInteger(1);
                        List<CategoryAttribute> categoryAttributes = new ArrayList<>();
                        modifyCategory.getAttributeIds().forEach(attributeId -> {
                            CategoryAttribute categoryAttribute = new CategoryAttribute();
                            categoryAttribute.setId(idGenerator.nextId());
                            categoryAttribute.setCategoryId(modifyCategory.getId());
                            categoryAttribute.setAttributeId(attributeId);
                            categoryAttribute.setIsRequired(attributeMap.get(attributeId));
                            categoryAttribute.setSort(sort.getAndIncrement());
                            categoryAttribute.setCreatedBy(modifiedBy);
                            categoryAttribute.setModifiedBy(modifiedBy);
                            categoryAttributes.add(categoryAttribute);
                        });
                        int insertBatch = categoryAttributeMapper.insertBatch(categoryAttributes);
                        logger.info("编辑商品分类-添加本次额外选择的商品关联属性-insertBatch={}", insertBatch);
                    }
                }
            } else {
                // 清空商品分类已关联的的属性
                int updatedStatusNum = categoryAttributeMapper.updateStatusByCategoryById(modifyCategory.getId(), modifiedBy);
                logger.info("编辑商品分类-清空商品分类已关联的的属性-updatedStatusNum={}", updatedStatusNum);
            }

        }
        return updated;
    }

    @Override
    public int deleteCategory(Long id) {
        int count = categoryMapper.selectCountById(id);
        if (count > MyConstants.IT1) {
            throw new IllegalArgumentException("请删除子分类后重试");
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        return categoryMapper.deleteCategoryById(id, modifiedBy);
    }

}
